package com.jessefyz.module.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageHelper;
import com.jessefyz.common.exception.CustomException;
import com.jessefyz.common.exception.DataNotFoundException;
import com.jessefyz.common.utils.DateUtils;
import com.jessefyz.module.member.service.IMemberInfoService;
import com.jessefyz.module.shop.common.utils.OrderUtil;
import com.jessefyz.module.shop.constants.OrderConstants;
import com.jessefyz.module.shop.domain.LitemallOrder;
import com.jessefyz.module.shop.domain.LitemallOrderGoods;
import com.jessefyz.module.shop.mapper.LitemallOrderMapper;
import com.jessefyz.module.shop.notify.NotifyService;
import com.jessefyz.module.shop.req.OrderPay;
import com.jessefyz.module.shop.req.OrderRefund;
import com.jessefyz.module.shop.req.OrderShip;
import com.jessefyz.module.shop.service.ILitemallGoodsProductService;
import com.jessefyz.module.shop.service.ILitemallOrderGoodsService;
import com.jessefyz.module.shop.service.ILitemallOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2020-03-11
 */
@Service
public class LitemallOrderServiceImpl extends ServiceImpl<LitemallOrderMapper, LitemallOrder> implements ILitemallOrderService
{

    @Autowired
    private ILitemallOrderGoodsService litemallOrderGoodsService;
    @Autowired
    private ILitemallGoodsProductService litemallGoodsProductService;

    @Autowired
    private IMemberInfoService memberInfoService;

    @Autowired
    private NotifyService notifyService;

    @Autowired
    private WxPayService wxPayService;

    /**
     * 查询订单
     *
     * @param id 订单ID
     * @return 订单
     */
    @Override
    public LitemallOrder selectLitemallOrderById(Long id)
    {
        LitemallOrder order =  this.baseMapper.selectLitemallOrderById(id);
        if (null == order) {
            throw new DataNotFoundException("订单不存在");
        }
        order.setGoodsVoList(this.litemallOrderGoodsService.selectLitemallOrderGoodsList(
                LitemallOrderGoods.builder()
                        .orderId(order.getId())
                        .build()
        ));
        return order;
    }

    /**
     * 查询订单列表
     *
     * @param litemallOrder 订单
     * @return 订单
     */
    @Override
    public List<LitemallOrder> selectLitemallOrderList(LitemallOrder litemallOrder)
    {
        List<LitemallOrder> litemallOrders = baseMapper.selectLitemallOrderList(litemallOrder);
        for (LitemallOrder order : litemallOrders) {
            order.setGoodsVoList(this.litemallOrderGoodsService.selectLitemallOrderGoodsList(
                    LitemallOrderGoods.builder()
                    .orderId(order.getId())
                    .build()
            ));
            order.setOrderHandleOption(OrderConstants.build(order));
        }
        return litemallOrders;
    }

    /**
     * 新增订单
     *
     * @param litemallOrder 订单
     * @return 结果
     */
    @Override
    public int insertLitemallOrder(LitemallOrder litemallOrder)
    {
        return baseMapper.insertLitemallOrder(litemallOrder);
    }

    /**
     * 修改订单
     *
     * @param litemallOrder 订单
     * @return 结果
     */
    @Override
    public int updateLitemallOrder(LitemallOrder litemallOrder)
    {
        litemallOrder.setUpdateTime(DateUtils.getNowDate());
        return baseMapper.updateLitemallOrder(litemallOrder);
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单ID
     * @return 结果
     */
    @Override
    public int deleteLitemallOrderByIds(Long[] ids)
    {
        return baseMapper.deleteLitemallOrderByIds(ids);
    }

    /**
     * 删除订单信息
     *
     * @param id 订单ID
     * @return 结果
     */
    @Override
    public int deleteLitemallOrderById(Long id)
    {
        return baseMapper.deleteLitemallOrderById(id);
    }

    /**
     * @Description 订单发货
     * @Author Jesse
     * @Date 2021-09-03
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void ship(OrderShip orderShip) {
        LitemallOrder order = Optional.ofNullable(this.getById(orderShip.getId()))
                .orElseThrow(() -> new DataNotFoundException("订单数据不存在"));
        if (!order.getOrderStatus().equals(OrderConstants.STATUS_PAY)) {
            throw new CustomException("状态异常：订单状态为”已付款“才可以发货");
        }
        BeanUtil.copyProperties(orderShip,order);
        order.setShipTime(new Date());
        order.setUpdateTime(new Date());
        order.setOrderStatus(OrderConstants.STATUS_SHIP);
        if (!this.updateById(order)) {
            throw new CustomException("发货异常，请联系管理员");
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 发货会发送通知短信给用户:          *
        // "您的订单已经发货，快递公司 {1}，快递单 {2} ，请注意查收"
        //notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{orderShip.getShipChannel(), orderShip.getShipSn()});
    }

    /**
     * @Description 订单线下收款
     * @Author Jesse
     * @Date 2021-09-03
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(OrderPay orderPay) {
        LitemallOrder order = Optional.ofNullable(this.getById(orderPay.getId()))
                .orElseThrow(()-> new DataNotFoundException("订单数据不存在"));
        if (!order.getOrderStatus().equals(OrderConstants.STATUS_CREATE)) {
            throw new CustomException( "当前订单状态不支持线下收款");
        }
        BeanUtil.copyProperties(orderPay,order);
        order.setOrderStatus(OrderConstants.STATUS_PAY);
        order.setUpdateTime(new Date());
        order.setPayTime(new Date());
        if (!this.updateById(order)) {
            throw new CustomException("发货异常，请联系管理员");
        }
    }

    /**
     * @Description 退款
     * @Author Jesse
     * @Date 2021-09-03
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(OrderRefund orderRefund) {
        LitemallOrder order = Optional.ofNullable(this.getById(orderRefund.getId()))
                .orElseThrow(()-> new DataNotFoundException("订单数据不存在"));
        if (!OrderConstants.isRefundStatus(order)) {
            throw new CustomException( "退款申请中状态下订单才可以审核退款");
        }
        BeanUtil.copyProperties(orderRefund,order);
        Date now = new Date();
        order.setOrderStatus(OrderConstants.STATUS_REFUND_CONFIRM);
        order.setUpdateTime(now);
        order.setRefundTime(now);
        order.setCloseTime(now);
        //修改数据库
        if (!this.updateById(order)) {
            throw new CustomException("退款异常，请联系管理员");
        }
        // 商品货品数量增加
        List<LitemallOrderGoods> orderGoodsList = litemallOrderGoodsService.list(new LambdaQueryWrapper<LitemallOrderGoods>()
            .eq(LitemallOrderGoods::getOrderId,order.getId())
        );
        for (LitemallOrderGoods orderGoods : orderGoodsList) {
            Long productId = orderGoods.getProductId();
            Integer number = orderGoods.getNumber();
            if (litemallGoodsProductService.addStock(productId, number) == 0) {
                throw new RuntimeException("商品货品库存增加失败");
            }
        }
        // 返还优惠券
//        List<LitemallCouponUser> couponUsers = couponUserService.findByOid(orderId);
//        for (LitemallCouponUser couponUser: couponUsers) {
//            // 优惠券状态设置为可使用
//            couponUser.setStatus(CouponUserConstant.STATUS_USABLE);
//            couponUser.setUpdateTime(LocalDateTime.now());
//            couponUserService.update(couponUser);
//        }

        if (1 == orderRefund.getRefundType().intValue()) {
            //原路退回的话要调用支付商接口
            // 微信退款
            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
            wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
            wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
            // 元转成分
            Integer totalFee = order.getActualPrice().multiply(new BigDecimal(100)).intValue();
            wxPayRefundRequest.setTotalFee(totalFee);
            wxPayRefundRequest.setRefundFee(totalFee);
            WxPayRefundResult wxPayRefundResult;
            try {
                wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
            } catch (WxPayException e) {
                throw new CustomException("订单退款失败");
            }
            if (!"SUCCESS".equals(wxPayRefundResult.getReturnCode())) {
                throw new CustomException("订单退款失败");
            }
            if (!"SUCCESS".equals(wxPayRefundResult.getResultCode())) {
                throw new CustomException("订单退款失败");
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功，请耐心等待到账。”
        // 注意订单号只发后6位
        /*notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND,
                new String[]{order.getOrderSn().substring(8, 14)});*/

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LitemallOrder findById(Integer userId, Integer orderId) {
        return this.getOne(new LambdaQueryWrapper<LitemallOrder>()
                .eq(LitemallOrder::getId,orderId)
                .eq(LitemallOrder::getUserId,userId)
                ,false);
    }

    @Override
    public List<LitemallOrder> queryByOrderStatus(Integer userId, List<Integer> orderStatus, Integer page, Integer limit, String sort, String order) {
        PageHelper.startPage(page, limit);
        return this.list(new LambdaQueryWrapper<LitemallOrder>()
            .eq(null != userId && 0 != userId,LitemallOrder::getUserId,userId)
            .in(CollectionUtil.isNotEmpty(orderStatus),LitemallOrder::getOrderStatus,orderStatus)
            .orderByDesc(LitemallOrder::getAddress)
        );
    }

    @Override
    public int updateWithOptimisticLocker(LitemallOrder order) {
        Date preUpdateTime = order.getUpdateTime();
        order.setUpdateTime(new Date());
        return (this.updateById(order))?1:0;
    }

    //这里应该产生一个唯一的订单，但是实际上这里仍然存在两个订单相同的可能性
    @Override
    public String generateOrderSn(Integer userId) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");
        String now = df.format(LocalDate.now());
        String orderSn = now + getRandomNum(6);
        while (countByOrderSn(userId, orderSn) != 0) {
            orderSn = now + getRandomNum(6);
        }
        return orderSn;
    }
    private String getRandomNum(Integer num) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
    public int countByOrderSn(Integer userId, String orderSn) {
        return count(new LambdaQueryWrapper<LitemallOrder>()
            .eq(LitemallOrder::getUserId,userId)
            .eq(LitemallOrder::getOrderSn,orderSn)
        );
    }

    @Override
    public LitemallOrder findBySn(String orderSn) {
        return this.getOne(new LambdaQueryWrapper<LitemallOrder>()
                .eq(LitemallOrder::getOrderSn,orderSn)
                ,false);
    }

    @Override
    public Map<Object, Object> orderInfo(Long userId) {
        List<LitemallOrder> orders = this.list(new LambdaQueryWrapper<LitemallOrder>()
            .eq(LitemallOrder::getUserId,userId)
        );

        int unpaid = 0;
        int unship = 0;
        int unrecv = 0;
        int uncomment = 0;
        for (LitemallOrder order : orders) {
            if (OrderUtil.isCreateStatus(order)) {
                unpaid++;
            } else if (OrderUtil.isPayStatus(order)) {
                unship++;
            } else if (OrderUtil.isShipStatus(order)) {
                unrecv++;
            } else if (OrderUtil.isConfirmStatus(order) || OrderUtil.isAutoConfirmStatus(order)) {
                uncomment += order.getComments();
            } else {
                // do nothing
            }
        }

        Map<Object, Object> orderInfo = new HashMap<Object, Object>();
        orderInfo.put("unpaid", unpaid);
        orderInfo.put("unship", unship);
        orderInfo.put("unrecv", unrecv);
        orderInfo.put("uncomment", uncomment);
        return orderInfo;

    }



    @Override
    public List<LitemallOrder> queryUnconfirm(Integer days) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expired = now.minusDays(days);
        return this.list(new LambdaQueryWrapper<LitemallOrder>()
            .eq(LitemallOrder::getOrderStatus,OrderUtil.STATUS_SHIP)
            .lt(LitemallOrder::getShipTime,expired.format(DateUtils.getDateTimeFormater(null)))
        );
    }

    @Override
    public List<LitemallOrder> queryComment(Integer orderComment) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expired = now.minusDays(orderComment);
        return this.list(new LambdaQueryWrapper<LitemallOrder>()
                .gt(LitemallOrder::getComments,0)
                .lt(LitemallOrder::getConfirmTime,expired.format(DateUtils.getDateTimeFormater(null)))
        );
    }
}
